home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
mach
/
sun4.md
/
machAsmDefs.h
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
14KB
|
459 lines
/*
* machAsmDefs.h --
*
* Machine-dependent macros.
*
* Copyright (C) 1985 Regents of the University of California
* All rights reserved.
*
*
* $Header: /cdrom/src/kernel/Cvsroot/kernel/mach/sun4.md/machAsmDefs.h,v 9.4 91/10/18 01:23:01 dlong Exp $ SPRITE (Berkeley)
*/
#ifndef _MACHASMDEFS
#define _MACHASMDEFS
#ifdef KERNEL
#include <vmSunConst.h>
#include <machConst.h>
#else
#include <kernel/vmSunConst.h>
#include <kernel/machConst.h>
#endif
/*
* Wait the 3 instructions necessary to allow a newly-written state register
* to settle.
*/
#define MACH_WAIT_FOR_STATE_REGISTER() \
nop; \
nop; \
nop
/*
* Bump the invalid window forward one. This is done by changing the
* invalid window mask. We shift the invalid window bit left by 1,
* but modulo the number of implemented windows.
*/
#define MACH_ADVANCE_WIM(REG1, REG2) \
mov %wim, REG1; \
sethi %hi(_machWimShift), REG2; \
ld [REG2 + %lo(_machWimShift)], REG2; \
sll REG1, REG2, REG2; \
srl REG1, 0x1, REG1; \
or REG1, REG2, REG1; \
mov REG1, %wim; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Move the invalid window backwards one. This is done by changing the
* invalid window mask. We shift the invalid window bit right by 1,
* but modulo the number of implemented windows.
*/
#define MACH_RETREAT_WIM(REG1, REG2) \
mov %wim, REG1; \
sethi %hi(_machWimShift), REG2; \
ld [REG2 + %lo(_machWimShift)], REG2; \
srl REG1, REG2, REG2; \
sll REG1, 0x1, REG1; \
or REG1, REG2, REG1; \
mov REG1, %wim; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Set the window invalid mask to point to the current window.
*/
#define MACH_SET_WIM_TO_CWP() \
mov %psr, %VOL_TEMP1; \
set 0x1, %VOL_TEMP2; \
sll %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP1; \
mov %VOL_TEMP1, %wim; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Test whether we're in an invalid window. If we are in an invalid window,
* then the condition codes should indicate a not zero ("bne" instruction
* will branch).
*/
#define MACH_INVALID_WINDOW_TEST() \
mov %psr, %VOL_TEMP1; \
set 0x1, %VOL_TEMP2; \
sll %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP1; \
mov %wim, %VOL_TEMP2; \
andcc %VOL_TEMP1, %VOL_TEMP2, %g0
/*
* Test whether we're about to encounter a window underflow condition.
* We put current cwp into temp1. We shift a one by that many bits.
* Then we shift it again, to "advance" the window by one. We and it
* with the valid window bits to get it modulo the number of windows - 1.
* Then we compare it with current wim to see if they're the same. If
* so, then we would get an underflow if we did a restore operation.
* If we are in an underflow situation, then the condition codes should
* indicate a not zero ("bne" instruction will branch).
*/
#define MACH_UNDERFLOW_TEST() \
mov %psr, %VOL_TEMP1; \
set 0x1, %VOL_TEMP2; \
sll %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP1; \
sethi %hi(_machWimShift), %VOL_TEMP2; \
ld [%VOL_TEMP2 + %lo(_machWimShift)], %VOL_TEMP2; \
srl %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP2; \
sll %VOL_TEMP1, 0x1, %VOL_TEMP1; \
or %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
mov %wim, %VOL_TEMP2; \
andcc %VOL_TEMP1, %VOL_TEMP2, %g0
/*
* The sequence we need to go through to restore the psr without restoring
* the old current window number. We want to remain in our current window.
* 1) Get old psr. 2) Clear only its cwp bits. 3) Get current psr.
* 4) Grab only its cwp bits. 5) Stick the two together and put it in
* the psr reg. 6) Wait for the register to be valid.
*/
#define MACH_RESTORE_PSR() \
mov %CUR_PSR_REG, %VOL_TEMP2; \
set (~MACH_CWP_BITS), %VOL_TEMP1; \
and %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP2; \
mov %psr, %VOL_TEMP1; \
and %VOL_TEMP1, MACH_CWP_BITS, %VOL_TEMP1; \
or %VOL_TEMP2, %VOL_TEMP1, %VOL_TEMP2; \
mov %VOL_TEMP2, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Save global registers.
* Store-doubles are faster and we do this from even register boundaries.
* For now, we only save the globals here, since the locals and ins will
* be saved on normal save-window operations. Note that this means the
* stack pointer and MACH_GLOBALS_OFFSET must be double-word aligned.
*/
#define MACH_SAVE_GLOBAL_STATE() \
add %sp, MACH_GLOBALS_OFFSET, %VOL_TEMP1; \
std %g0, [%VOL_TEMP1]; \
std %g2, [%VOL_TEMP1 + 8]; \
std %g4, [%VOL_TEMP1 + 16]; \
std %g6, [%VOL_TEMP1 + 24]
/*
* Restore the global registers. We do load doubles here for speed
* for even-register boundaries. For now, we only restore the globals
* from here, since the locals and ins will be restored as part of the
* normal restore window operations. Note that this means the stack pointer
* and MACH_GLOBALS_OFFSET must be double-word aligned.
*/
#define MACH_RESTORE_GLOBAL_STATE() \
add %sp, MACH_GLOBALS_OFFSET, %VOL_TEMP1; \
ldd [%VOL_TEMP1], %g0; \
ldd [%VOL_TEMP1 + 8], %g2; \
ldd [%VOL_TEMP1 + 16], %g4; \
ldd [%VOL_TEMP1 + 24], %g6
/*
* Save r16 to r23 (locals) and r24 to r31 (ins) to 16 words at
* the top of this window's stack.
*/
#define MACH_SAVE_WINDOW_TO_STACK() \
std %r16, [%sp]; \
std %r18, [%sp + 8]; \
std %r20, [%sp + 16]; \
std %r22, [%sp + 24]; \
std %r24, [%sp + 32]; \
std %r26, [%sp + 40]; \
std %r28, [%sp + 48]; \
std %r30, [%sp + 56]
#define MACH_RESTORE_WINDOW_FROM_STACK() \
ldd [%sp], %r16; \
ldd [%sp + 8], %r18; \
ldd [%sp + 16], %r20; \
ldd [%sp + 24], %r22; \
ldd [%sp + 32], %r24; \
ldd [%sp + 40], %r26; \
ldd [%sp + 48], %r28; \
ldd [%sp + 56], %r30
#define MACH_SAVE_WINDOW_TO_BUFFER(reg1) \
std %r16, [reg1]; \
std %r18, [reg1 + 8]; \
std %r20, [reg1 + 16]; \
std %r22, [reg1 + 24]; \
std %r24, [reg1 + 32]; \
std %r26, [reg1 + 40]; \
std %r28, [reg1 + 48]; \
std %r30, [reg1 + 56]
/*
* Clear out the local and out registers for a new window to move into
* or a window we're moving out of.
* Outs: r8 to r15, locals: r16 to r23.
*/
#define MACH_CLEAR_WINDOW() \
clr %r8; \
clr %r9; \
clr %r10; \
clr %r11; \
clr %r12; \
clr %r13; \
clr %r14; \
clr %r15; \
clr %r16; \
clr %r17; \
clr %r18; \
clr %r19; \
clr %r20; \
clr %r21; \
clr %r22; \
clr %r23
/*
* Enabling and disabling traps.
*/
#define MACH_ENABLE_TRAPS(useReg) \
mov %psr, useReg; \
or useReg, MACH_ENABLE_TRAP_BIT, useReg; \
mov useReg, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Should I use xor here and MACH_ENABLE_TRAP_BIT?
*/
#define MACH_DISABLE_TRAPS(useReg1, useReg2) \
mov %psr, useReg1; \
set MACH_DISABLE_TRAP_BIT, useReg2; \
and useReg1, useReg2, useReg1; \
mov useReg1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Equivalents to C macros for enabling and disabling interrupts.
* They aren't quite equivalent, since they don't do panic's on negative
* disable counts. These macros should really only be used for debugging,
* in any case.
*/
#define DISABLE_INTR_ASM(reg1, reg2, NoDisableLabel) \
set _mach_AtInterruptLevel, reg1; \
ld [reg1], reg1; \
tst reg1; \
bne NoDisableLabel; \
nop; \
mov %psr, reg1; \
set MACH_DISABLE_INTR, reg2; \
or reg1, reg2, reg1; \
mov reg1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER(); \
set _mach_NumDisableIntrsPtr, reg1; \
ld [reg1], reg2; \
add reg2, 0x1, reg2; \
st reg2, [reg1]; \
NoDisableLabel:
#define ENABLE_INTR_ASM(reg1, reg2, NoEnableLabel) \
set _mach_AtInterruptLevel, reg1; \
ld [reg1], reg1; \
tst reg1; \
bne NoEnableLabel; \
nop; \
set _mach_NumDisableIntrsPtr, reg1; \
ld [reg1], reg2; \
sub reg2, 0x1, reg2; \
st reg2, [reg1]; \
tst reg2; \
bne NoEnableLabel; \
nop; \
mov %psr, reg1; \
set MACH_ENABLE_INTR, reg2; \
and reg1, reg2, reg1; \
mov reg1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER(); \
NoEnableLabel:
/*
* Enable interrupts and keep traps enabled.
* Uses given register.
*/
#define QUICK_ENABLE_INTR(reg) \
mov %psr, reg; \
andn reg, MACH_DISABLE_INTR, reg; \
mov reg, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Disable interrupts and keep traps enabled.
* Uses given register.
*/
#define QUICK_DISABLE_INTR(reg) \
mov %psr, reg; \
or reg, MACH_DISABLE_INTR, reg; \
mov reg, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Set interrupts to a particular value. This is useful for a routine that
* just wants to save the value, change it, and then reset it without worrying
* about whether this turns interrupts on or off.
*/
#define SET_INTRS_TO(regValue, useReg1, useReg2) \
mov %psr, useReg1; \
set MACH_ENABLE_INTR, useReg2; \
and useReg1, useReg2, useReg1; \
set MACH_DISABLE_INTR, useReg2; \
and regValue, useReg2, useReg2; \
or useReg1, useReg2, useReg1; \
mov useReg1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Run at high priority: supervisor mode, interrupts disabled, traps enabled.
* This must be done in 2 steps - 1) leaving traps off, if they were off,
* set new interrupt level. 2) Enable traps. This keeps us from getting
* an interrupt at the old level rather than the new right after enabling
* traps.
*/
#define MACH_SR_HIGHPRIO() \
mov %psr, %VOL_TEMP1; \
set (MACH_DISABLE_INTR | MACH_SUPER_BIT), %VOL_TEMP2; \
or %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
mov %VOL_TEMP1, %psr; \
or %VOL_TEMP1, MACH_ENABLE_TRAP_BIT, %VOL_TEMP1; \
mov %VOL_TEMP1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Run at low supervisor priority: supervisor mode, interrupts enabled, traps
* enabled. As described above for MACH_SR_HIGHPRIO, we must do this in
* 2 steps.
*/
#define MACH_SR_LOWPRIO() \
mov %psr, %VOL_TEMP1; \
set MACH_SUPER_BIT, %VOL_TEMP2; \
or %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
set MACH_ENABLE_INTR, %VOL_TEMP2; \
and %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
mov %VOL_TEMP1, %psr; \
or %VOL_TEMP1, MACH_ENABLE_TRAP_BIT, %VOL_TEMP2; \
mov %VOL_TEMP1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* Run at user priority: user mode, traps on.
*/
#define MACH_SR_USERPRIO() \
mov %psr, %VOL_TEMP1; \
set MACH_ENABLE_TRAP_BIT, %VOL_TEMP2; \
or %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
set (~MACH_SUPER_BIT), %VOL_TEMP2; \
and %VOL_TEMP1, %VOL_TEMP2, %VOL_TEMP1; \
mov %VOL_TEMP1, %psr; \
MACH_WAIT_FOR_STATE_REGISTER()
/*
* For sticking debug info into a buffer. After each value, stamp a special
* mark, which gets overwritten by the next value, so we always know where
* the end of the list is.
*/
#define MACH_DEBUG_BUF(reg1, reg2, DebugLabel, stuff) \
set _debugCounter, reg1; \
ld [reg1], reg1; \
sll reg1, 2, reg1; \
set _debugSpace, reg2; \
add reg2, reg1, reg2; \
st stuff, [reg2]; \
set _debugCounter, reg1; \
ld [reg1], reg1; \
add reg1, 1, reg1; \
set 500, reg2; \
subcc reg2, reg1, %g0; \
bgu DebugLabel; \
nop; \
clr reg1; \
DebugLabel: \
set _debugCounter, reg2; \
st reg1, [reg2]; \
sll reg1, 2, reg1; \
set _debugSpace, reg2; \
add reg2, reg1, reg2; \
set 0x11100111, reg1; \
st reg1, [reg2]
#define MACH_DEBUG_ONCE(reg1, reg2, NoMoreLabel, DebugLabel, stuff, a_num)\
set _debugCounter, reg1; \
ld [reg1], reg1; \
cmp reg1, a_num; \
bg NoMoreLabel; \
nop; \
MACH_DEBUG_BUF(reg1, reg2, DebugLabel, stuff); \
NoMoreLabel: \
nop
/*
* This is the equivalent to a call to VmmachGetPage followed by a test on
* the returned pte to see if it is resident and user readable and writable.
* This is used where a call to the vm code won't work since output registers
* aren't available. This sets the condition codes so that 0 is returned
* if the address is resident and not protected and not zero is returned if
* a fault would occur.
*/
#define MACH_CHECK_FOR_FAULT(checkReg, reg1) \
set VMMACH_PAGE_MAP_MASK, reg1; \
and checkReg, reg1, reg1; \
lda [reg1] VMMACH_PAGE_MAP_SPACE, reg1; \
srl reg1, VMMACH_PAGE_PROT_SHIFT, reg1; \
cmp reg1, VMMACH_PTE_OKAY_VALUE
/*
* This is similar to the above macro, except that it is intended for checking
* stack pointers to see if a restore of a window would page fault. We check
* the value of the stack pointer, and the offset of the window size.
*/
#define MACH_CHECK_STACK_FAULT(checkReg, reg1, ansReg, reg2, TestAgainLabel, LastOKLabel) \
clr ansReg; \
set VMMACH_PAGE_MAP_MASK, reg1; \
and checkReg, reg1, reg1; \
lda [reg1] VMMACH_PAGE_MAP_SPACE, reg1; \
srl reg1, VMMACH_PAGE_PROT_SHIFT, reg1; \
cmp reg1, VMMACH_PTE_OKAY_VALUE; \
be TestAgainLabel; \
nop; \
set 0x2, ansReg; \
TestAgainLabel: \
set VMMACH_PAGE_MAP_MASK, reg1; \
add checkReg, (MACH_SAVED_WINDOW_SIZE - 4), reg2; \
and reg2, reg1, reg1; \
lda [reg1] VMMACH_PAGE_MAP_SPACE, reg1; \
srl reg1, VMMACH_PAGE_PROT_SHIFT, reg1; \
cmp reg1, VMMACH_PTE_OKAY_VALUE; \
be LastOKLabel; \
nop; \
or ansReg, 0x4, ansReg; \
LastOKLabel: \
tst ansReg
/*
* Get a ptr to the pcb structure of the current process.
* Return this in reg1
*/
#define MACH_GET_CUR_PROC_PTR(reg1) \
set _proc_RunningProcesses, reg1; \
ld [reg1], reg1; \
ld [reg1], reg1
/*
* Get a ptr to the Mach_State struct of the current process. Put it in reg1.
*/
#define MACH_GET_CUR_STATE_PTR(reg1, reg2) \
MACH_GET_CUR_PROC_PTR(reg1); \
set _machStatePtrOffset, reg2; \
ld [reg2], reg2; \
add reg1, reg2, reg1; \
ld [reg1], reg1
#endif /* _MACHASMDEFS */